package cn.koala.key.configure;

import cn.koala.key.common.jwt.JwtHandlerInterceptorAdapter;
import cn.koala.key.common.utils.EhiHttpServletRequestWrapper;
import cn.seed.common.core.ApolloBaseConfig;
import cn.seed.common.core.Result;
import cn.seed.common.core.ResultCode;
import cn.seed.common.core.ResultGenerator;
import cn.seed.common.utils.SignUtils;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;

/**
 * Spring MVC 配置
 */
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

	private static final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);

	/**
	 * 添加拦截器
	 * @param registry
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 接口签名认证拦截器，该签名认证比较简单，实际项目中可以使用Json Web Token或其他更好的方式替代。
		registry.addInterceptor(new JwtHandlerInterceptorAdapter()).excludePathPatterns("/druid/**")
		.excludePathPatterns("/v2/**")
		.excludePathPatterns("/swagger-resources/**")
		.excludePathPatterns("/monitor/**").excludePathPatterns("/login").excludePathPatterns("/")
		.excludePathPatterns("/error/**").excludePathPatterns("/heartbeat").excludePathPatterns("/loginmain");
		// 开发环境忽略签名认证
		if (!"dev".equals(ApolloBaseConfig.getPlatForm())) {
			registry.addInterceptor(new HandlerInterceptorAdapter() {
				@Override
				public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
						throws Exception {
					// 验证签名
					EhiHttpServletRequestWrapper ehiHttpServletRequestWrapper = new EhiHttpServletRequestWrapper(
							request);
					if (validateSign(ehiHttpServletRequestWrapper)) {
						return true;
					} else {
						logger.warn("签名认证失败，请求接口：{}，请求IP：{}，请求参数：{}", request.getRequestURI(), getIpAddress(request),
								JSON.toJSONString(request.getParameterMap()));
						responseResult(response, ResultGenerator.genFailResult(ResultCode.UNAUTHORIZED, "签名认证失败"));
						return false;
					}
				}
			}).excludePathPatterns("/druid/*").excludePathPatterns("/heartbeat");
		}
	}

	private void responseResult(HttpServletResponse response, Result result) {
		response.setCharacterEncoding("UTF-8");
		response.setHeader("Content-type", "application/json;charset=UTF-8");
		response.setStatus(200);
		try {
			response.getWriter().write(JSON.toJSONString(result));
		} catch (IOException ex) {
			logger.error(ex.getMessage());
		}
	}

	/**
	 * 一个简单的签名认证，规则： 1. 将请求参数按ascii码排序 2. 拼接为a=value&b=value...这样的字符串（不包含sign） 3.
	 * 混合密钥（secret）进行md5获得签名，与请求的签名进行比较
	 */
	private boolean validateSign(EhiHttpServletRequestWrapper request) {
		// 获得请求签名，如sign=19e907700db7ad91318424a97c54ed57
		String requestSign = request.getHeader("Content-MD5");

		BufferedReader br;
		String bodyStr = "";
		try {
			br = request.getReader();
			String str;
			while ((str = br.readLine()) != null) {
				bodyStr += str;
			}

		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		String query = request.getQueryString();
		if (StringUtils.isEmpty(requestSign) && StringUtils.isEmpty(query) && StringUtils.isEmpty(bodyStr)) {
			return false;
		}
		String sign = SignUtils.sign(query, bodyStr);
		logger.info(sign);
		logger.info(requestSign);
		// 比较
		return StringUtils.equals(sign.toLowerCase(), requestSign.toLowerCase());
	}

	private String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		// 如果是多级代理，那么取第一个ip为客户端ip
		if (ip != null && ip.indexOf(",") != -1) {
			ip = ip.substring(0, ip.indexOf(",")).trim();
		}

		return ip;
	}
	@Bean
	public FilterRegistrationBean filterRegistrationBean() {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
		filterRegistrationBean.setFilter(new CommonFilter());
		filterRegistrationBean.addUrlPatterns("/*");
		filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,");
		return filterRegistrationBean;
	}

	/**
	 * 解决跨域问题
	 * @param registry
	 */
	@Override
	public void addCorsMappings(CorsRegistry registry) {
	}


}
